#pragma once
#ifndef COLOR_SPACE_READ_H
#define COLOR_SPACE_READ_H

#include "ReadInBits.h"
#include "ShortReadUtil.h"
#include "stdafx.h"

/*
 * This file provides functions translated from base space to color space and vice versa
 * encoded class CReadInBits.
 */

// The first base is encoded in first bit returned CReadInBits
CReadInBits colors2Bases(CReadInBits readInColors);

// Translate color read in B0123 format to CReadInBits
bool encodeColors(const char* colorsStr, CReadInBits&  readInColors);
bool encodeColorsNas3(const char* colorsStr, CReadInBits&  readInColors);
// Translate color read in readInBits format to c_str in B0123 format
char* decodeColors(char* colorsStr, CReadInBits readInColors);

inline char* decodeColorReadWithPrimer(char* caRead, CReadInBits readInColors)
{
    decodeColors(&(caRead[1]), readInColors);
    caRead[0] = caRead[1]; // Mimic the first base from the primer
    caRead[1] = '0';
    return(caRead);
}

char* correctAndDecodeRead \
(CReadInBits readInColors, CReadInBits refInColors, bool correct, char* caRead, char* caQscore);

// Encode the first base in the first bit
inline CReadInBits bases2Colors(CReadInBits readInBase)
{
    CReadInBits readInColor;
    //Note the first bits store the first bases of the read. The following bits are color transition
    readInColor.UpperBits = readInBase.UpperBits ^(readInBase.UpperBits << 1);
    readInColor.LowerBits = readInBase.LowerBits ^(readInBase.LowerBits << 1);
    //Note the most significant digit is useless
    return(readInColor);
}

// Don't encode the first base in the first bit, colors only
inline CReadInBits bases2PureColors(CReadInBits readInBase)
{
    CReadInBits readInColor;
    //Note the first bits store the first bases of the read. The following bits are color transition
    readInColor.UpperBits = readInBase.UpperBits ^(readInBase.UpperBits >> 1);
    readInColor.LowerBits = readInBase.LowerBits ^(readInBase.LowerBits >> 1);
    //Note the most significant digit is useless
    return(readInColor);
}

// reverse colors signals. (The reverse compliment of a read
inline CReadInBits reversePureColors(CReadInBits readInPureColors, unsigned int colorsLength)
{
    CReadInBits reverseColors;
    // Note the first bits store the first bases of the read. The following bits are color transition
    unsigned int tailLength = (wordSize - colorsLength);
    reverseColors.UpperBits = (reverse64bits(readInPureColors.UpperBits) >> tailLength);
    reverseColors.LowerBits = (reverse64bits(readInPureColors.LowerBits) >> tailLength);
    //Note the most significant digit is useless
    return(reverseColors);
}

// Correct the single mismatched from the read in color.
// SNP_FLAG is a bits string as flag that should take from the readInColors (SNP caused color mismatches)
inline CReadInBits correctReadInColorSpace(CReadInBits readInColors, CReadInBits refInColors, WORD_SIZE SNP_FLAG)
{
    CReadInBits correctedReadInColors;
    correctedReadInColors.UpperBits = (readInColors.UpperBits & SNP_FLAG) | (refInColors.UpperBits & ~SNP_FLAG);
    correctedReadInColors.LowerBits = (readInColors.LowerBits & SNP_FLAG) | (refInColors.LowerBits & ~SNP_FLAG) ;
    return(correctedReadInColors);
}

// use a matrix for translate a base and color to the next base
// translate a base and color to the next base
const static char base_transfer_matrix[][4] = {{ 'A', 'C' , 'G', 'T' },
    { 'C', 'A' , 'T', 'G' }, { 'G', 'T', 'A', 'C' }, { 'T', 'G', 'C', 'A' }
};
inline char base2Color(char base, char color)
{
    switch (base) {
    case 'A':
    case 'a':
        return (base_transfer_matrix[0][color - '0']);
    case 'C':
    case 'c':
        return (base_transfer_matrix[1][color - '0']);
    case 'G':
    case 'g':
        return (base_transfer_matrix[2][color - '0']);
    case 'T':
    case 't':
        return (base_transfer_matrix[3][color - '0']);
    default:
        return(0);
    }
}

// If there are two consecutive mismatched colors, check if it is a valid SNP.
// Return # of mismatches or -1 -2 -3 for valid to represent Complement, Transversion or Transition.
int getSNPtype(CReadInBits readInColors, CReadInBits refInColors);
//  Translate the -1 -2 -3 to a character as flag
inline char returnSNPtype(CReadInBits readInColors, CReadInBits refInColors)
{
    int diffOrSNPFLag = getSNPtype(readInColors, refInColors);
    switch (diffOrSNPFLag) {
    case -1:
        return('C');
    case -2:
        return('V');
    case -3:
        return('T');
    default:
        return('N');
    }
}

inline int returnSNPtype(char c)
{
    switch (c) {
    case 'C':
        return(1);
    case 'V':
        return(2);
    case 'T':
        return(3);
    default:
        return(0);
    }
}

// correct the single mismatches in the
int correctReadInColorSpace(CReadInBits readInColors, CReadInBits refInColors, CReadInBits& correctedRead);
void colorQV2baseQV(CReadInBits readInColors, CReadInBits& correctedRead, char* Qscores);
bool colorQV2baseQV(WORD_SIZE singleColorErrorflag, char* Qscores, unsigned int readLength);

inline void setFirstBase(char c, CReadInBits& readInBase)
{
    switch (c) {
    case 'a':
    case 'A':
        readInBase.UpperBits &= (~0x01);
        readInBase.LowerBits &= (~0x01);
        break;
    case 'c':
    case 'C':
        readInBase.UpperBits &= (~0x01);
        readInBase.LowerBits |= 0x01;
        break;
    case 'g':
    case 'G':
        readInBase.UpperBits |= 0x01;
        readInBase.LowerBits &= (~0x01);
        break;
    case 't':
    case 'T':
        readInBase.UpperBits |= 0x01;
        readInBase.LowerBits |= 0x01;
        break;
    default:
        cout << "Unknown character" << endl;
    }
}

void assertSNP(int SNPType, CReadInBits refInColors, CReadInBits crInColors);

// Given strings in bases, return the corresponding color signal in A=0 C=1 G=2, T=3 Format
string readInBases2ColorsInACGT_Format(string readInBases);
// Given color Read in ACGT Format, return correspond string in A=0 C=1 G=2, T=3 Format
// Note the first base is duplicated.
string colorReadInACGTto0123Format(string colorReadInACGT);

#endif /* COLOR_SPACE_READ_H */


